package cn.mulanbay.auth.controller;

import cn.mulanbay.auth.bean.request.AdminLoginRequest;
import cn.mulanbay.auth.bean.request.LoginRequest;
import cn.mulanbay.auth.handler.LogHandler;
import cn.mulanbay.auth.service.AuthService;
import cn.mulanbay.business.bean.LoginUser;
import cn.mulanbay.business.bean.UserLoginInfo;
import cn.mulanbay.business.handler.CacheHandler;
import cn.mulanbay.business.handler.PasswordHandler;
import cn.mulanbay.business.handler.TokenHandler;
import cn.mulanbay.common.bean.ResultBean;
import cn.mulanbay.common.config.CacheKey;
import cn.mulanbay.common.exception.ApplicationException;
import cn.mulanbay.common.exception.ErrorCode;
import cn.mulanbay.common.util.IPAddressUtil;
import cn.mulanbay.common.util.StringUtil;
import cn.mulanbay.persistent.entity.User;
import cn.mulanbay.persistent.enums.UserStatus;
import cn.mulanbay.persistent.enums.UserType;
import cn.mulanbay.web.bean.UserCommonRequest;
import cn.mulanbay.web.controller.BaseController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 *
 * @author fenghong
 * @create 2022-01-16 10:00
 */
@RefreshScope
@RestController
public class AuthController extends BaseController {

    /**
     * 登录最大失败次数
     */
    @Value("${security.login.maxFail}")
    private int loginMaxFail;

    /**
     * 管理员是否需要检查验证码
     */
    @Value("${security.login.admin.verifyCode:false}")
    private boolean adminVerifyCode;

    @Autowired
    AuthService authService;

    @Autowired
    CacheHandler cacheHandler;

    @Autowired
    TokenHandler tokenHandler;

    @Autowired
    PasswordHandler passwordHandler;

    @Autowired
    LogHandler logHandler;

    /**
     * 管理员登陆
     *
     * @return
     */
    @RequestMapping(value = "/loginAuth", method = RequestMethod.POST)
    public ResultBean loginAuth(@RequestBody @Valid AdminLoginRequest login) {
        if(adminVerifyCode){
            //判定验证码
            String verifyKey = CacheKey.getKey(CacheKey.CAPTCHA_CODE, login.getUuid());
            String serverCode = cacheHandler.getForString(verifyKey);
            if (StringUtil.isEmpty(serverCode) || !serverCode.equals(login.getCode())) {
                return callbackErrorCode(ErrorCode.USER_VERIFY_CODE_ERROR);
            }
        }
        return this.doLogin(login, UserType.ADMIN);
    }

    /**
     * 用户登陆
     *
     * @return
     */
    @RequestMapping(value = "/userLogin", method = RequestMethod.POST)
    public ResultBean userLogin(@RequestBody @Valid LoginRequest login) {
        return this.doLogin(login,UserType.USER);
    }

    private ResultBean doLogin(LoginRequest login,UserType loginType){
        String username = login.getUsername();
        //错误次数验证(为避免恶意登录，可以加上ip，即:ip+username)
        String failKey = CacheKey.getKey(CacheKey.USER_LOGIN_FAIL, username);
        Integer fails = cacheHandler.get(failKey, Integer.class);
        if (fails != null && fails >= loginMaxFail) {
            return callbackErrorCode(ErrorCode.USER_LOGIN_FAIL_MAX);
        }
        //用户验证
        User user = authService.getUser(login.getUsername());
        if (user == null) {
            return callbackErrorCode(ErrorCode.USER_NOTFOUND);
        } else {
            if (user.getStatus() == UserStatus.DISABLE) {
                return callbackErrorCode(ErrorCode.USER_IS_STOP);
            }
            if (user.getExpireTime() != null && user.getExpireTime().isBefore(LocalDateTime.now())) {
                return callbackErrorCode(ErrorCode.USER_EXPIRED);
            }
            // 检测密码
            String rp = user.getPassword();
            String encodePassword = passwordHandler.encodePassword(login.getPassword());
            if (!rp.equalsIgnoreCase(encodePassword)) {
                if (fails == null) {
                    fails = 1;
                } else {
                    fails++;
                }
                cacheHandler.set(failKey, fails, 300);
                return callbackErrorCode(ErrorCode.USER_PASSWORD_ERROR);
            }
            String token = doLogin(user,loginType);
            Map map = new HashMap<>();
            map.put("token", token);
            return callback(map);
        }
    }

    /**
     * 登录
     *
     * @param user
     */
    private String doLogin(User user,UserType loginType) {
        //更新登录信息
        LoginUser lu = tokenHandler.createLoginUser(user);
        //管理员登录
        if(loginType==UserType.ADMIN){
            //获取管理员角色信息
            Long roleId = authService.getUserRoleId(user.getId());
            if(roleId==null){
                throw new ApplicationException(ErrorCode.USER_ROLE_IS_NULL);
            }
            lu.setRoleId(roleId);
        }
        String token = tokenHandler.createToken(lu);

        //更新登录日志
        UserLoginInfo uli = new UserLoginInfo();
        uli.setUserId(user.getId());
        uli.setLoginIp(IPAddressUtil.getIpAddress(request));
        uli.setLoginTime(LocalDateTime.now());
        uli.setLoginToken(lu.getLoginToken());
        uli.setLoginType(loginType);
        logHandler.addUserLogin(uli);
        return token;
    }

    /**
     * 登出
     * @param uc
     * @return
     */
    @RequestMapping(value = "/logout", method = RequestMethod.POST)
    public ResultBean logout(UserCommonRequest uc) {
        String token = this.getToken(request);
        tokenHandler.deleteLoginUser(token);
        if (uc.getUserId() != null) {
            //authService.deleteLastLoginToken(uc.getUserId());
        }
        return callback(null);
    }

    /**
     * 从header里面获取
     *
     * @param request
     * @return
     */
    private String getToken(HttpServletRequest request) {
        String token = request.getHeader(CacheKey.HEADER);
        if (StringUtil.isNotEmpty(token) && token.startsWith(CacheKey.TOKEN_PREFIX)) {
            token = token.replace(CacheKey.TOKEN_PREFIX, "");
        }
        return token;
    }

}
